package com.study.online.web;

import com.study.online.redis.MessageReceiveHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 用于处理websocket 聊天室
 *
 * @author: chenhs
 * @date: Created in 11:00 2020/1/2
 **/
@Component
public class ChatHandler extends TextWebSocketHandler {

    @Autowired
    private RedisMessageListenerContainer container;
    @Autowired
    private MessageListenerAdapter listenerAdapter;


    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * roomId --> 该房间内所有用户连接
     */
    public static ConcurrentHashMap<String, Set<WebSocketSession>> roomUserMap = new ConcurrentHashMap<>();

    /**
     * 1.建立连接
     *
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //StandardWebSocketSession[id=fe75341d-f2d8-ba96-1f07-416a43295f01, uri=ws://127.0.0.1:8080/chat?userId=3048&roomId=10001]
        UriComponents uriComponents = UriComponentsBuilder.fromUri(session.getUri()).build();
        String roomId = uriComponents.getQueryParams().getFirst("roomId");

        //保存session
        String key = "room:" + roomId;
        roomUserMap.putIfAbsent(key, new HashSet<>());
        roomUserMap.get(key).add(session);

        //todo 房间和服务器建立连接的时候，需要订阅 聊天频道
        System.out.println("新的用户来了：" + session);

        container.addMessageListener(listenerAdapter, new PatternTopic(key));
    }


    @Autowired
    MessageReceiveHandler handler;

    /**
     * 2.数据交互
     *
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

        System.out.println(session);
        System.out.println(message);

        //收到消息，广播给房间里每一个人
        UriComponents uriComponents = UriComponentsBuilder.fromUri(session.getUri()).build();
        String roomId = uriComponents.getQueryParams().getFirst("roomId");
        String userId = uriComponents.getQueryParams().getFirst("userId");
        String key = "room:" + roomId;

        //todo 消息过滤，第三词脱敏 *** 。。。

        //发消息到redis中指定房间频道
        redisTemplate.convertAndSend(key, message.getPayload());

        String mett = handler.getMessage();
        broadcastMessage(key, mett);
    }

    /**
     * 3.连接断开-退出房间
     *
     * @param session
     * @param status
     * @throws Exception
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

        UriComponents uriComponents = UriComponentsBuilder.fromUri(session.getUri()).build();
        String roomId = uriComponents.getQueryParams().getFirst("roomId");

        //移除session
        String key = "room:" + roomId;
        roomUserMap.get(key).remove(session);

        System.out.println("用户走了：" + session);
    }

    /**
     * 4.推送其他人发的消息到用户客户端上面
     *
     * @param key
     * @param message
     * @throws IOException
     */
    public void broadcastMessage(String key, String message) throws IOException {
        //消息来源---redis---订阅指定房间频道

        Set<WebSocketSession> sessions = roomUserMap.get(key);
        for (WebSocketSession webSocketSession : sessions) {
            webSocketSession.sendMessage(new TextMessage(message));
        }

    }

}
